package com.icesoft.wechat.service.impl;

import com.icesoft.framework.core.cache.RedisCacheManager;
import com.icesoft.framework.core.exception.BusinessException;
import com.icesoft.framework.core.vo.Status;
import com.icesoft.system.auth.AuthProperties;
import com.icesoft.system.auth.entity.AuthToken;
import com.icesoft.system.auth.entity.LoginUser;
import com.icesoft.system.auth.service.LoginService;
import com.icesoft.system.entity.Account;
import com.icesoft.system.service.impl.AccountServiceImpl;
import com.icesoft.system.service.impl.CompanyServiceImpl;
import com.icesoft.system.types.AuthTypeDictionary;
import com.icesoft.system.types.SystemSettingTypeDictionary;
import com.icesoft.system.types.UserTypeDictionary;
import com.icesoft.system.util.JwtUtil;
import com.icesoft.system.util.PasswordUtil;
import com.icesoft.system.util.SecurityUtils;
import com.icesoft.system.vo.CompanyVO;
import com.icesoft.wechat.applet.entity.WechatAuthorizationCode;
import com.icesoft.wechat.applet.service.ApiWechatApplet;
import com.icesoft.wechat.auth.WechatCredential;
import com.icesoft.wechat.entity.WechatUser;
import com.icesoft.wechat.service.WechatUserDaoListener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class WechatLoginService {

	private final LoginService loginService;


	private final ApiWechatApplet apiWechatApplet;

	private final WechatUserServiceImpl wechatUserService;

	private final UserTypeDictionary userTypeDictionary;

	private final SystemSettingTypeDictionary systemSettingTypeDictionary;

	private final AuthTypeDictionary authTypeDictionary;

	private final AccountServiceImpl accountService;

	private final AuthProperties authProperties;

	private final RedisCacheManager redisCacheManager;

	private final CompanyServiceImpl companyService;

	public WechatAuthorizationCode getWechatAuthorizationCode(WechatCredential wechatCredential) throws Exception {
		CompanyVO company = companyService.findByAppletAppid(wechatCredential.getAppId());
		return apiWechatApplet.decode(wechatCredential.getEncryptedData(), wechatCredential.getIv(), wechatCredential.getCode(), wechatCredential.getRawData(), wechatCredential.getSignature(), company.getAppletAppid(), company.getAppletSecret());
	}

	public WechatUser login(WechatCredential wechatCredential) throws Exception {
		CompanyVO company = companyService.findByAppletAppid(wechatCredential.getAppId());
		WechatAuthorizationCode wechatAuthorizationCode = getWechatAuthorizationCode(wechatCredential);
		String openId = wechatAuthorizationCode.getOpenid();
		WechatUser wechatUser = wechatUserService.lambdaQuery().eq(WechatUser::getPhone, wechatAuthorizationCode.getPhoneNumber()).eq(WechatUser::getAppId, wechatCredential.getAppId()).one();

		if (wechatUser == null) {
			throw new BusinessException(Status.FAIL_INVALID_ACCOUNT, "用户不存在");
		} else {
			Account openIdAccount = accountService.lambdaQuery().eq(Account::getUserId, wechatUser.getId()).eq(Account::getAuthAccount, openId).one();
			if (openIdAccount == null) {
				wechatUser.setOpenId(openId);
				wechatUserService.updateEntity(wechatUser);
				openIdAccount = new Account();
				openIdAccount.setUserId(wechatUser.getId());
				openIdAccount.setUserType(userTypeDictionary.getWechat());
				openIdAccount.setAuthAccount(openId);
				openIdAccount.setSecretSalt("icesoft-wechat-user");
				openIdAccount.setAuthSecret(PasswordUtil.md5(systemSettingTypeDictionary.getDefaultPassword() + openIdAccount.getSecretSalt()));
				openIdAccount.setAuthType(authTypeDictionary.getAccount());
				accountService.createEntity(openIdAccount);
			}
			Account phoneAccount = accountService.lambdaQuery().eq(Account::getUserId, wechatUser.getId()).eq(Account::getAuthAccount, wechatAuthorizationCode.getPhoneNumber()).one();
			if (phoneAccount == null) {
				phoneAccount = new Account();
				phoneAccount.setUserId(wechatUser.getId());
				phoneAccount.setUserType(userTypeDictionary.getWechat());
				phoneAccount.setSecretSalt("icesoft-wechat-user");
				phoneAccount.setAuthAccount(wechatAuthorizationCode.getPhoneNumber());
				phoneAccount.setAuthSecret(PasswordUtil.md5(systemSettingTypeDictionary.getDefaultPassword() + phoneAccount.getSecretSalt()));
				phoneAccount.setAuthType(authTypeDictionary.getPhone());
				accountService.createEntity(phoneAccount);
			}
			openIdAccount = accountService.lambdaQuery()
					.eq(Account::getUserId, wechatUser.getId())
					.eq(Account::getAuthAccount, openId)
					.eq(Account::getUserType, userTypeDictionary.getWechat())
					.one();
			String token = loginService.createTokenAndLogin(openIdAccount, wechatUser);
			wechatUser.setToken(token);
			wechatUserService.updateEntity(wechatUser);
			return wechatUser;
		}
	}

	public LoginUser<WechatUser> refreshToken(String token) throws Exception {
		WechatUser wechatUser = wechatUserService.lambdaQuery().eq(WechatUser::getToken, token).one();
		if (wechatUser != null) {
			Account account = accountService.lambdaQuery()
					.eq(Account::getUserId, wechatUser.getId())
					.eq(Account::getAuthAccount, wechatUser.getOpenId())
					.one();
			LoginUser<WechatUser> wechatUserLoginUser = loginService.renderLoginUser(account, wechatUser);
			WechatUser user = wechatUserLoginUser.getUser();
			String newToken = JwtUtil.createJWT(account.getAuthAccount(), "back", user.getClass().getSimpleName(), this.authProperties.getExpireTime() * 1000L);
			AuthToken jwtToken = new AuthToken(newToken, wechatUserLoginUser);
			jwtToken.setValidPassword(false);
			user.setToken(jwtToken.getToken());
			wechatUserService.updateEntity(wechatUser);
			wechatUserLoginUser.setUser(user);
			SecurityUtils.getSubject().login(jwtToken);
			redisCacheManager.deleteObject(token);
			redisCacheManager.setCacheObject(token, wechatUserLoginUser, authProperties.getExpireTime(), TimeUnit.MINUTES);
			return wechatUserLoginUser;
		}
		throw new BusinessException("未找到用户");
	}
}
